Hemos llegado lejos con nuestro blog, pero todavía contiene demasiado código para una aplicación tan simple. Por el camino, hemos desarrollado un sistema simple de redirección y un método para utilizar plantillas (con las funciones ob_start() y ob_get_clean()). Si se quisiera seguir implementando este framework de cero, se podrían al menos emplear los componentes de Symfony: Routing y Templating.
Como ya tenemos claro que no queremos reinventar la rueda, vamos a dejar que Symfony2 se ocupe de los problemas más comunes. Vamos a ver la misma aplicación, nuestro blog, construida con Symfony2.
El primer paso será por tanto "instalar" Symfony2. Para ello seguimos los pasos explicados con anterioridad.
Una vez tenemos nuestro nuevo proyecto de symfony, podremos apreciar que la estructura es muy similar al framework que habíamos comenzado a construir para nuestro blog. Algo importante es que el Front Controller en Symfony2, app.php o app_dev.php para producción y desarrollo respectivamente, se encuentra dentro del directorio "/web", por lo que sería interesante cambiar la ruta del virtual host creado en el servidor de apache para que apuntara directamente a dicho directorio.
De este modo, accediendo a "http://blog.localhost/app_dev.php" (o el nombre que se le haya dado al host virtual), accedemos al proyecto de symfony.
Como nuestro blog necesita acceso a base de datos, debemos configurar la información de conexión (app\config\parameters.yml).
Creando el bundle
Ahora que ya tenemos symfony preparado, creemos el bundle que formará nuestro blog. Usaremos la consola de Symfony2. Abrimos una consola en el directorio raíz de nuestro proyecto y ejecutamos:
Ese comando nos enseñará las opciones que ofrece la consola. Como lo que queremos es crear nuestro primer bundle, nos interesa el comando "generate:bundle":
El "namespace" permite organizar de manera limpia nuestros bundles y "format" define YAML como lenguaje de marcado. Symfony nos va preguntando por diferentes opciones. Dejamos las que vienen por defecto que son las que le hemos dado. Al final, nos pregunta si queremos actualizar tanto el Kernel como el Routing. Decimos que sí a ambos y comprobamos como actualiza "app/AppKernel.php" y "app/config/routing.yml" para añadir nuestro bundle.
La opción "resource" indica dónde va a buscar la configuración de rutas de nuestro bundle, en este caso en: "@BloggerBlogBundle/Resources/config/routing.yml". Ahí es donde indicaremos qué controlador tomará el control según la ruta pedida:
Además tenemos otro fichero de rutas dentro de la carpeta "app/config". En este fichero se cargan las rutas de cada uno de los bundles y, además, la opción "prefix" permite montar todo el sistema de redirección de nuestro bundle con un prefijo. En nuestro caso lo hemos dejado en "/" pero si por ejemplo se quisiera que todas las rutas de nuestro blog se accedieran a través de "/blogger" se podría cambiar aquí. Puede ser útil si se genera por ejemplo un bundle de administración del sitio web.
Por defecto, Symfony2 nos crea un controlador, unas vistas y el controlador de test (DefaultController.php, views/Default y DefaultControllerTest). Los borramos para poner nuestro blog.
Una vez preparada la estructura, añadimos el contenido de nuestro bundle. Comenzamos con el controlador:
Las dos acciones del controlador siguen siendo ligeras. Cada una emplea la librería Doctrine ORM para recuperar objetos de la base de datos y el componente Templating emplea las plantillas para devolver un objeto Response. Pero si hablamos de recuperar información, aunque no pensemos en base de datos, debemos tener un objeto con el que representar en este caso los posts. Creamos esta clase dentro de una carpeta "Entity" dentro del bundle:
Pero Doctrine no solo permite recuperar filas de la base de datos, permite recuperar e introducir objetos completos. Para poder hacerlo, se debe indicar a Doctrine a qué corresponde cada cosa mediante lo que es un mapeo de los componentes y propiedades:
Y ya para terminar con la preparación de Doctrine, nos falta crear los "Getters" y "Setters" que accedan a las propiedades de la clase (ya que las propiedades están protegidas). Para ello empleamos la consola:
Existe también la posibilidad de crear la entidad con los atributos deseados mediante symfony desde consola de la siguiente forma:
...y con:
...actualizamos la base de datos para que se corresponda con las entidades creadas.
Pasemos ahora a las vistas. El método render() crea un objeto Response con el contenido generado por la plantilla. El controlador ejecutará la plantilla "BloggerBlogBundle:Blog:show.html.php" que sigue la siguiente convención de nomenclatura:
Ese nombre lógico es mapeado a la siguiente ruta física:
Por otro lado, la plantilla de listado es ahora con Symfony2 algo más sencilla:
La plantilla padre, ::layout.html.php, no hace mención ni al BundleName ni al ControllerName (los dos doble puntos (::) al comienzo) lo que significa que está ubicada fuera de los bundles, y más concretamente en el directorio "app":
Si intentamos acceder a nuestro blog, veremos que no carga bien las plantillas. Esto se debe a que por defecto Symfony2 trabaja con un sistema de plantillas que emplea la tecnología "twig". Más adelante veremos como emplear dicho sistema, pero por el momento indicaremos a symfony que queremos usar PHP para nuestras plantillas en el fichero de configuración:
La modificación de la plantilla show es trivial, basándose en la de listado. Como ejercicio (pista: cuando de error, formatear fecha [->format('d-m-Y')].
Mejorando las plantillas
Symfony2 viene de serie con motor de plantillas llamado Twig que permite crearlas más rápidamente y las hace más sencillas. Veamos como quedaría la plantilla de listado de nuestro blog (ahora con menos líneas todavía):
El comando extends define una plantilla padre, en este caso la disposición de la página (layout) sobre la que se incluirán los elementos de la plantilla. Por otro lado, el comando block define los bloques de código que se incluirán en el "layout" de la página, de quien es responsabilidad presentar dicha información:
La modificación de la plantilla que muestra la información de cada post de nuevo es trivial. Como ejercicio (pista: cuando de error, formatear fecha [|date('d-m-Y')].
Por último indicamos en el BlogController que queremos usar la plantilla de Twig en lugar de la de PHP. Ahora podemos eliminar tanto las plantillas como el layout de PHP.
Mejorando la visualización: Estructura de 3 niveles
Ya que Twig permite la herencia de plantillas, vamos a emplear la aproximación de Estructura de 3 niveles. Esta aproximación nos permite modificar las vistas en 3 niveles dentro de la aplicación, permitiendo mucha flexibilidad.
Plantilla principal - Nivel 1
Empecemos creando una base de visualización para nuestro blog. Necesitamos dos ficheros aquí, la plantilla y el CSS. Como Symfony2 soporta HTML5, también haremos uso de el.
Hay 3 ficheros externos que pedimos en esta plantilla, 1 JavaScript y 2 CSS. El fichero de JavaScript soluciona algunos problemas de falta de soporte de HTML5 en el navegador IE en sus versiones anteriores a la 9. Los 2 ficheros CSS importan fuentes de Google Web font.
El tag {{ se emplea para imprimir el valor de una variable o expresión. Por ejemplo "{{ asset('css/screen.css') }}" se usa para devolver el valor de la función asset, que proporciona una forma flexible de referenciar a la carpeta "web" de nuestro proyecto, para referenciar recursos de nuestra aplicación como imágenes, hojas de estilos o ficheros JavaScript. Además, el tag {{ puede combinarse con filtros (e.g., {{ blog.created|date("d-m-Y") }}) antes de imprimir el resultado. Para una lista completa de estos filtros, se puede acudir a la documentación de Twig.
Después añadimos una hoja de estilos "screen.css" dentro de la carpeta "web/css":
Y referenciamos a nuestra nueva base de visualización en nuestras dos plantillas (list.html.twig y show.html.twig):
Comprobamos el resultado.
Plantilla del bundle - Nivel 2
Añadimos:
Parece muy simple y puede parecer innecesaria. Pero, ¿qué nos ofrece este segundo nivel? Al no añadir el contenido del sidebar en la principal, abstraemos a la plantilla principal del contenido del bundle. Pero, ¿por qué no poder ese contenido en las diferentes vistas del bundle? Imaginemos que queremos personalizar el sidebar para algunas páginas, o que queremos cambiar este o el footer. En vez de hacerlo en cada una de las plantillas, lo podríamos hacer en esta única plantilla común a todas.
Plantilla de la página - Nivel 3
Nuestras vistas "list.html.twig" y "show.html.twig", dentro de "src/Blogger/BlogBundle/Resources/views". Las modificamos para que hereden de la de nivel 2, layout.html.twig:
... que a su vez hereda de la de nivel 1, base.html.twig.
Y con esto tenemos un blog que empieza a tener algo más de color (literalmente).
Añadiendo la ruta de nuestro blog como página de inicio de Symfony2
Ahora que tenemos nuestro blog en marcha, vamos a hacer que la página de inicio de nuestro proyecto symfony sea el blog. Para ello, actualizamos el fichero de rutas (routing.yml) que se encuentra dentro del bundle:
Después, eliminamos la ruta por defecto de symfony que lleva a la página de bienvenida a Symfony2, del fichero de rutas "app/config/routing_dev.yml":
Y eliminamos también el bundle que venía por defecto en la instalación "AppBundle".
El blog en el entorno de producción
Si accedemos a nuestro blog a través del Front Controller de producción (app.php) a través de la ruta "http://symfony.blog/app.php/blog", nos dará error. Esto se debe a que en el entorno de desarrollo se limpia la cache cada vez que hay un cambio en la configuración, mientras que en el entorno de producción no para optimizar. Para solucionarlo, debemos limpiar la caché del entorno de producción:
Además, gracias a la directiva "RewriteRule ^(.*)$ app.php [QSA,L]" que hemos puesto en el ".htaccess", podremos acceder directamente a través de la ruta "http://blog.localhost/".
Por el momento nuestro blog simplemente muestra un listado de posts y el detalle de cada uno de ellos. Veamos como aumentar el contenido de nuestro sitio web "Añadiendo nuevas páginas".